# %%
# 1. 什么是高阶函数和闭包并举例说明。
# 1A：高阶函数：如果函数的参数中包含其他函数，则该函数是高阶函数
def isNum(num):
    try:
        float(num)
    except ValueError:
        return False
    else:
        return True

def filterNum(list, fun): # filterNum就是高阶函数
    new_list = []
    for i in list:
        if fun(i):
            new_list.append(i)
    return new_list

#  闭包：闭包出现在内层嵌套函数调用外层函数的变量时，延伸了变量的作用域，用.__closure__可以判断

def fun1():
    a = []
    def fun2(num):
        a.append(num) # 变量a出现了闭包
        print(a)
    return fun2


# 2. 请列出functools包内的每个函数的功能作用。
# 2A： reduce/partial/lru_cache least-recently-used
from functools import reduce
s = sum(range(10))
print(s)
s = reduce(lambda x,y: print(x,y), range(10), 100)
print(s)

from functools import partial
def add(x:int, y):
    return x + y

foo = partial(add, 4)
foo(5)

import inspect
sig =  inspect.signature(add)
print(sig)

from functools import lru_cache
import time

@lru_cache
def add(x, y=5):
    print('-' * 30)
    time.sleep(2)
    return x + y

# 3. 请使用已学习的装饰器相关知识自己实现functools.lru_cache。

from functools import wraps
import time,inspect

# 无参装饰器
def my_lru_cache(fn):
    buffer = dict()
    # @wraps(fn)
    def wrapper(*args, **kwargs):
        parakey = []
        for x in args:
            parakey.append(x)
            for y in kwargs:
                parakey.append(y)
        if str(parakey) in buffer.keys():
            return buffer[str(parakey)]
        else:
            res = fn(*args, **kwargs)
            buffer[str(parakey)] = res
            print('-'*30)
            time.sleep(2)
            return res
    return wrapper

@my_lru_cache
def add(x, y):
    return x + y

print(add(0,2))
print(add(0,2))


# 带参装饰器，实现控制buffersize

def my_lru_cache(buffersize = 1024):
    def _my_lru_cache(fn):
        buffer = dict()
        # @wraps(fn)
        def wrapper(*args, **kwargs):
            parakey = []
            for x in args:
                parakey.append(x)
                for y in kwargs:
                    parakey.append(y)
            if str(parakey) in buffer.keys():
                print('-'*30 + '缓存' + str(parakey))
                return buffer[str(parakey)]
            else:
                if len(buffer) >= buffersize:
                    buffer.popitem()
                res = fn(*args, **kwargs)
                buffer[str(parakey)] = res
                print('-'*30+'重新计算'+str(parakey))
                time.sleep(2)
                return res
        return wrapper
    return _my_lru_cache

@my_lru_cache(1)
def add(x, y):
    return x + y


print(add(4,1))
print(add(4,2))
print(add(4,2))
print(add(4,3))
print(add(4,3))
print(add(4,1))


# 4. 什么是类型注解并说明其背后的目的。
# 4A: python一切皆变量，所以在定义变量或函数时使用类型注释对变量或函数返回值进行备注， 例如
#对变量进行注释：
x:int =3
def add(x:int, y:int = 5) -> int: 
    return x+y

add(1)

